package com.acwing.partition12;

import java.io.*;

/**
 * @author `RKC`
 * @date 2022/1/18 16:14
 */
public class AC1144连接格点 {

    private static final int N = 1010, M = 2 * N * N;
    private static final int[][] dirs = {{-1, 0, 1}, {0, 1, 2}, {1, 0, 1}, {0, -1, 2}};
    private static int n = 0, m = 0, cnt = 0;

    private static int[][] edges = new int[M][3];

    private static int[][] ids = new int[N][N];
    private static UnionFind uf = new UnionFind(N * N);

    private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    private static final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) throws IOException {
        String[] s = reader.readLine().split("\\s+");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        for (int i = 1, id = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) ids[i][j] = id++;
        }
        while (true) {
            String str = reader.readLine();
            if (str == null || str.isEmpty()) break;
            s = str.split("\\s+");
            //将输入的坐标点映射成一维的id，并先连接这些必须连接的边
            int x1 = Integer.parseInt(s[0]), y1 = Integer.parseInt(s[1]), x2 = Integer.parseInt(s[2]), y2 = Integer.parseInt(s[3]);
            uf.union(ids[x1][y1], ids[x2][y2]);
        }
        //初始化其它的边
        init();
        //对其它的边做一次kruskal
        writer.write(kruskal() + "\n");
        writer.flush();
    }

    private static void init() {
        //边权只有1和2，先把边权为1的全部处理出来再处理边权为2的，后续进行kruskal就省去了一步排序的操作
        for (int k = 0; k < 2; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                    for (int z = 0; z < dirs.length; z++) {
                        if (z % 2 == k) {
                            int x = i + dirs[z][0], y = j + dirs[z][1], w = dirs[z][2];
                            if (x == 0 || x > n || y == 0 || y > m) continue;
                            int id1 = ids[i][j], id2 = ids[x][y];
                            if (id1 < id2) edges[cnt++] = new int[]{id1, id2, w};
                        }
                    }
                }
            }
        }
    }

    private static int kruskal() {
        //边的预处理已经是顺序存放，所以不需要再进行排序
        int answer = 0;
        for (int i = 0; i <= cnt; i++) {
            int u = edges[i][0], v = edges[i][1], w = edges[i][2];
            if (uf.find(u) != uf.find(v)) {
                uf.union(u, v);
                answer += w;
            }
        }
        return answer;
    }

    private static class UnionFind {
        private int[] parent;

        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) parent[i] = i;
        }

        public int find(int x) {
            if (x == parent[x]) return x;
            return parent[x] = find(parent[x]);
        }

        public void union(int x, int y) {
            int a = find(x), b = find(y);
            if (a != b) parent[b] = a;
        }
    }
}
